﻿using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using YaAppoint.Appointments.CheckIn;
using YaAppoint.CustomSettings;
using YaAppoint.ExamAppies;
using YaAppoint.OnlineServiceCache;
using YaAppoint.PrintTemplates;
using YaAppoint.Response;
using YaAppoint.TextTemplates;

namespace YaAppoint.Appointments.SelfServiceTerminal
{
    public class SelfServiceAppService(ICheckInAppService checkInAppService,
                                       ICustomSettingAppService customSettingAppService,
                                       IRepository<ExamApplication, Guid> examApplicationRepository,
                                       IRepository<TextTemplate, Guid> textTemplateRepository,
                                       IRepository<PrintTemplate, Guid> printTemplateRepository,
                                       AsyncQueryableExecuter queryableExecuter,
                                       IOnlineServiceCacheAppService onlineServiceCacheService,
                                       IRepository<Room, Guid> roomRepository,
                                       IRepository<Department, Guid> departmentRepository,
                                       IMapper mapper,
                                       IRepository<Appointment, Guid> appointmentReposotory) : ApplicationService, ISelfServiceAppService, ITransientDependency
    {
        private readonly ICheckInAppService _checkInAppSerive = checkInAppService;
        private readonly IRepository<Appointment, Guid> _appointmentReposotory = appointmentReposotory;
        private readonly ICustomSettingAppService _settingAppService = customSettingAppService;
        private readonly IRepository<Department, Guid> _departmentRepository = departmentRepository;
        private readonly IMapper _mapper = mapper;
        private readonly IRepository<ExamApplication, Guid> _examApplicationRepository = examApplicationRepository;
        private readonly IRepository<Room, Guid> _roomRepository = roomRepository;
        private readonly AsyncQueryableExecuter _queryableExecuter = queryableExecuter;
        private readonly IRepository<PrintTemplate, Guid> _printTemplateRepository = printTemplateRepository;
        private readonly IRepository<TextTemplate, Guid> _textTemplateRepository = textTemplateRepository;
        private readonly IOnlineServiceCacheAppService _onlineServiceCacheService = onlineServiceCacheService;


        /// <summary>
        /// 预约签到
        /// </summary>
        public async Task<BackJson> CheckIn(string number, string depCodes)
        {
            var res = new BackJson();
            var appoint = await _appointmentReposotory.FirstOrDefaultAsync(a => a.Number == number);
            if (appoint == null)
            {
                res.code = 1;
                res.err = "预约不存在，请联系科室服务台";
                return res;
            }
            var printTemplate = await _printTemplateRepository.FirstOrDefaultAsync(p => p.DeviceTypeId == appoint.Pool.Device.DeviceTypeId
                                                                                     && p.DepartmentId == appoint.Pool.Device.DepartmentId
                                                                                     && p.PrintType == PrintType.CheckIn
                                                                                     && p.IsActive);
            if (printTemplate == null)
            {
                var departmemt = await _departmentRepository.GetAsync(a => a.Id == appoint.Pool.Device.DepartmentId);
                res.code = 2;
                res.err = $"找不到科室({departmemt.Name}下，设备类型：{appoint.Pool.Device.DeviceType.Name}的小票打印模板";
            }
            var remoteCheckInRes = await _checkInAppSerive.CheckInAsync(number);
            appoint.Status = AppointmentStatus.Achieve;
            await _appointmentReposotory.UpdateAsync(appoint);
            remoteCheckInRes.TemplateJsonStr = printTemplate!.JsonContent;
            res.code = 0;
            res.data = remoteCheckInRes;
            return res;
        }

        /// <summary>
        /// 获取预约信息
        /// </summary>
        public async Task<BackJson> GetAppointmentInfo(string number, string depCodes)
        {
            var res = new BackJson();
            var depCodeList = depCodes.Split(',').ToList();
            var depList = await _departmentRepository.GetListAsync(d => depCodeList.Contains(d.OuterCode!.ToString()));
            var depIdList = depList.Select(d => d.Id).ToList();

            //获取患者ID
            var applyItem = await _examApplicationRepository.FirstOrDefaultAsync(e => e.ApplyNumber.Equals(number)
                                                                            || e.MedicalCardNumber == number
                                                                            || (e.Appointment!=null && e.Appointment.Number ==number)
                                                                            || e.IdCardNumber == number
                                                                            || e.InPatientNumber == number
                                                                            || e.OuterNumber == number);
            if (applyItem == null)    
            {
                res.code = 1;
                res.err = "无患者预约信息";
                return res;
            }
            // 当前已签/可签的申请项目集合
            var itemQuery = await _examApplicationRepository.GetQueryableAsync();
            itemQuery = itemQuery.Where(e => e.PatientId == applyItem.PatientId)
                                  .Where(e => e.Appointment != null
                                            && e.Appointment.Status != AppointmentStatus.Cancel
                                            && e.Appointment.Pool.StartTime.Date == DateTime.Now.Date)
                                  .Where(e => depIdList.Contains(e.Appointment!.Pool.Device.DepartmentId));
            var examApplicationList = await _queryableExecuter.ToListAsync(itemQuery);
            if (examApplicationList == null || examApplicationList.Count == 0)
            {
                res.code = 2;
                res.err = "无可签或已签预约";
                return res;
            }
            // 从项目中提取去重后的预约
            var appointList = examApplicationList.DistinctBy(e => e.AppointmentId).ToList().Select(e => e.Appointment).ToList();
            // 当前可签
            List<Appointment> canCheckInAppointments = new List<Appointment>();
            foreach (var appointment in appointList)
            {
                var startTime = appointment!.Pool.StartTime;
                var setting = await _settingAppService.GetDeviceSetting(appointment.Pool.DeviceId);
                var startCheckInTime = startTime.AddMinutes(-(double)setting.Earliest!);
                if (startCheckInTime <= DateTime.Now && appointment.Pool.Date.Date == DateTime.Now.Date && appointment.Status == AppointmentStatus.Submit)
                {
                    canCheckInAppointments.Add(appointment);
                }
            }

            RomoteCheckInRes? romoteCheckInRes = null; 
            if (canCheckInAppointments.Count == 1) // 如果只有一个可签到的，那就直接去签到
            {
                var appoint = canCheckInAppointments[0];
                var printTemplate = await _printTemplateRepository.FirstOrDefaultAsync(t=>t.DeviceTypeId==appoint.Pool.Device.DeviceTypeId
                                                                                          && t.DepartmentId== appoint.Pool.Device.DepartmentId
                                                                                          && t.PrintType == PrintType.CheckIn
                                                                                          && t.IsActive);
                if (printTemplate != null)
                {
                    romoteCheckInRes = await _checkInAppSerive.CheckInAsync(appoint.Number);
                    romoteCheckInRes.TemplateJsonStr = printTemplate.JsonContent;
                    if (romoteCheckInRes.Succeed)
                    {
                        for (int i = 0; i < appointList.Count; i++)
                        {
                            if (appointList[i]!.Number == appoint.Number)
                            {
                                appointList[i]!.Status = AppointmentStatus.Achieve;
                            }
                        }
                        appoint.Status = AppointmentStatus.Achieve;
                        await _appointmentReposotory.UpdateAsync(appoint);
                    }
                }
                else
                {
                    var department = depList.First(d => d.Id == appoint.Pool.Device.DepartmentId);
                    romoteCheckInRes = new RomoteCheckInRes();
                    romoteCheckInRes.Succeed = false;
                    romoteCheckInRes.Error = $"科室({department.Name})下设备类型({appoint.Pool.Device.DeviceType.Name}) 无可用小票打印模板";
                }
            }
            res.code = 0;
            res.data = new
            {
                appoints = _mapper.Map<List<Appointment>, List<AppointmentDto>>(appointList!),
                patient = _mapper.Map<ExamApplication, ExamApplicationDto>(examApplicationList[0]),
                autoCheckInRes= romoteCheckInRes
            };
            return res;
        }

        /// <summary>
        /// 重新打印
        /// </summary>
        public async Task<BackJson> RePrint(string appointNumber)
        {
            var onlineService = await _textTemplateRepository.FirstOrDefaultAsync(t => t.Type == TemplateType.Service && t.Interface != null && t.Interface.Equals("ICheckInByApi") && t.IsActive);
            var res = new BackJson();
            BackJson onLineServiceRes;
            // 动态编译(使用api)
            if (onlineService != null)
            {
                // 从缓存中获取实例
                var cachedService = await _onlineServiceCacheService.GetOrAddOnlineService(_mapper.Map<TextTemplate, TextTemplateDto>(onlineService));
                if (cachedService.GetInstance() is ICheckInByApi service)
                {
                    onLineServiceRes = await service.Reprint(appointNumber);
                    // 获取预约
                    var appoint = await _appointmentReposotory.FirstOrDefaultAsync(a => a.Number == appointNumber);
                    var device = appoint!.Pool.Device;
                    var printTemplate = await _printTemplateRepository.FirstOrDefaultAsync(p => p.DeviceTypeId == device.DeviceTypeId
                                                                                             && p.DepartmentId == device.DepartmentId
                                                                                             && p.IsActive
                                                                                          );
                    string? templateJsonStr = null;
                    if (printTemplate != null)
                    {
                        templateJsonStr = printTemplate.JsonContent;
                    }
                    res.code = onLineServiceRes.code;
                    res.msg = onLineServiceRes.msg;
                    res.err = onLineServiceRes.err;
                    res.data = new
                    {
                        JsonStr = templateJsonStr,
                        CallBack = onLineServiceRes.data
                    };
                }
                else // 未实现接口异常
                {
                    throw new BusinessException(CustomErrorCodes.TemplateInterfaceUnimplemented)
                    {
                        Data = {
                            { "templateName",onlineService.Name},
                            { "interface",onlineService.Interface}
                        }
                    };
                }
            }
            else
            {
                res.code = 1;
                res.err = "未配置与pacs或叫号系统的在线服务！";
            }
            return res;
        }
    }
}
